/*
ont-space - The ontology-based resource metadata repository
Copyright (c) 2006-2008, Information Eng. Research Unit - Univ. of Alcalá
http://www.cc.uah.es/ie
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 2.1 of the License, or (at your option)
any later version.
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along
with this library; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package org.ontspace.sld.owl;

import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.ObjectProperty;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.Ontology;
import com.hp.hpl.jena.ontology.Ontology.*;
import com.hp.hpl.jena.rdf.model.NodeIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import java.net.URI;
import java.util.*;

import org.ontspace.sld.SLDQueryManager;
import org.ontspace.owl.MetadataRepositoryImpl;
import org.ontspace.owl.QueryManagerImpl;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.ontspace.MetadataRecordReference;
import org.ontspace.owl.MetadataRecordReferenceImpl;

public class SLDQueryManagerImpl extends QueryManagerImpl
        implements SLDQueryManager {

    private static MetadataRepositoryImpl _rep;
    private static List<Ontology> _onts =
            new ArrayList<Ontology>();
    private List<URI> _uriList;
    private String _nsName =
            "http://www.cc.uah.es/ie/ont/sld-ospace";
    private OntModel _OntModel;

    /** 
     * Creates a new instance of DCQueryManagerImpl
     */
    public SLDQueryManagerImpl(MetadataRepositoryImpl rep, HashMap params)
            throws ClassNotFoundException, NoSuchMethodException {
        super(rep);
        _rep =
                rep;
        this._uriList =
                new ArrayList<URI>();
        addRequiredOntologies(params);
    }

    /**
     * Adds the required ontology to the ontologies' list
     * @param ont Ontology to be added into the list
     */
    @Override
    public void addOntologyRef(Ontology ont) {
        if (ont != null) {
            _onts.add(ont);
        }
    }

    /**
     * Adds the required ontologies' URI to the object
     * @param params
     */
    private void addRequiredOntologies(HashMap params) {
        String ontologyUri;
        int i =
                1;
        boolean finished =
                false;
        while (!finished) {
            String paramName =
                    "uri" + i++;
            ontologyUri =
                    (String) params.get(paramName);
            if (ontologyUri != null) {
                try {
                    this._uriList.add(new URI(ontologyUri));
                } catch (URISyntaxException ex) {
                    Logger.getLogger(QueryManagerImpl.class.getName()).
                            log(Level.SEVERE, null, ex);
                }
            } else {
                finished =
                        true;
            }
        }
    }

    /**
     * Gets a list with the URIs of the ontologies required by the query manager
     * @return A list whith the USIs of the required ontologies
     */
    @Override
    public List<URI> getRequiredOntologies() {
        return this._uriList;
    }

    /**
     * Launches a query for  a particular element in the ontology    
     * @return SLDQueryResultImpl
     */
    public SLDQueryResultImpl queryLOwithSupportActivitiesExecutedByLearners() {
        System.out.println("Query not yet implemented");
        return null;
    }

    /**
     * Launches a query for  a particular element in the ontology    
     * @return SLDQueryResultImpl
     */
    public SLDQueryResultImpl queryLOWhichActsContainsDifferentsRoles() {
        System.out.println("Query not yet implemented");
        return null;
    }

    /**
     * Launches a query for  a particular element in the ontology    
     * @return SLDQueryResultImpl
     */
    public SLDQueryResultImpl queryLOWhichRolePartContainsLAandSA() {
        if (_OntModel == null) {
            this._OntModel =
                    this.getOntologyModel();
        }
        Boolean laB =
                false;
        Boolean saB =
                false;

        SLDQueryResultImpl queryResults =
                new SLDQueryResultImpl();

        Set<MetadataRecordReference> instancesR =
                new HashSet<MetadataRecordReference>();


        OntClass ld =
                _OntModel.getOntClass(_nsName + "#Learning-Design");
        ExtendedIterator ldInstances =
                ld.listInstances();


        while (ldInstances.hasNext()) {

            Individual ldInstance =
                    (Individual) ldInstances.next();

            ObjectProperty hasElement =
                    _OntModel.getObjectProperty(_nsName + "#method-ref");
            NodeIterator methodInstances =
                    ldInstance.listPropertyValues(hasElement);
            //for each element
            while (methodInstances.hasNext()) {
                Resource methodInstance =
                        (Resource) methodInstances.next();


                ObjectProperty propPlay =
                        _OntModel.getObjectProperty(_nsName + "#play-ref");
                StmtIterator playInstances =
                        methodInstance.listProperties(propPlay);

                while (playInstances.hasNext()) {
                    Statement playInstance =
                            playInstances.nextStatement();

                    ObjectProperty propAct =
                            _OntModel.getObjectProperty(_nsName + "#act-ref");
                    StmtIterator actInstances =
                            playInstance.getResource().listProperties(propAct);

                    while (actInstances.hasNext()) {
                        Statement actInstance =
                                actInstances.nextStatement();

                        ObjectProperty rolePartProp =
                                _OntModel.getObjectProperty(_nsName +
                                "#role-part-ref");
                        StmtIterator rpInstances =
                                actInstance.getResource().listProperties(rolePartProp);

                        while (rpInstances.hasNext()) {
                            Statement rpInstance =
                                    rpInstances.nextStatement();
                            ObjectProperty saProp =
                                    _OntModel.getObjectProperty(_nsName +
                                    "#support-activity-ref");
                            StmtIterator sa =
                                    null;
                            sa =
                                    rpInstance.getResource().listProperties(saProp);

                            if (sa.hasNext()) {
                                saB =
                                        true;
                            }

                            ObjectProperty laProp =
                                    _OntModel.getObjectProperty(_nsName +
                                    "#learning-activity-ref");
                            StmtIterator la =
                                    null;
                            la =
                                    rpInstance.getResource().listProperties(laProp);
                            if (la.hasNext()) {
                                laB =
                                        true;
                            }
                        }
                    }
                }
            }


            if ((saB) && (laB)) {
                MetadataRecordReference lor =
                        new MetadataRecordReferenceImpl(_rep.getRepositoryURI(),
                        ldInstance.getLocalName());
                if (!(queryResults.getMetadataRecordReference().contains(lor))) {
                    queryResults.getMetadataRecordReference().add(lor);
                }
            }
            saB =
                    false;
            laB =
                    false;
        }

        return queryResults;

    }

    /**
     * Launches a query for  a particular element in the ontology    
     * @return SLDQueryResultImpl
     */
    public SLDQueryResultImpl queryLOWithPlays(int numPlays) {
        int plays =
                0;

        if (_OntModel == null) {
            this._OntModel =
                    this.getOntologyModel();
        }
        Boolean laB =
                false;
        Boolean saB =
                false;

        SLDQueryResultImpl queryResults =
                new SLDQueryResultImpl();

        Set<MetadataRecordReference> instancesR =
                new HashSet<MetadataRecordReference>();


        OntClass ld =
                _OntModel.getOntClass(_nsName + "#Learning-Design");
        ExtendedIterator ldInstances =
                ld.listInstances();


        while (ldInstances.hasNext()) {

            Individual ldInstance =
                    (Individual) ldInstances.next();

            ObjectProperty hasElement =
                    _OntModel.getObjectProperty(_nsName + "#method-ref");
            NodeIterator methodInstances =
                    ldInstance.listPropertyValues(hasElement);
            //for each element
            while (methodInstances.hasNext()) {
                Resource methodInstance =
                        (Resource) methodInstances.next();


                ObjectProperty propPlay =
                        _OntModel.getObjectProperty(_nsName + "#play-ref");
                StmtIterator playInstances =
                        methodInstance.listProperties(propPlay);

                while (playInstances.hasNext()) {
                    Statement playInstance =
                            playInstances.nextStatement();
                    plays++;

                }//plays
            }//methods


            if (numPlays == plays) {
                MetadataRecordReference lor =
                        new MetadataRecordReferenceImpl(_rep.getRepositoryURI(),
                        ldInstance.getLocalName());
                if (!(queryResults.getMetadataRecordReference().contains(lor))) {
                    queryResults.getMetadataRecordReference().add(lor);
                }
            }
            saB =
                    false;
            laB =
                    false;
        }

        return queryResults;

    }

    /**
     * Launches a query for  a particular element in the ontology    
     * @return SLDQueryResultImpl
     */
    public SLDQueryResultImpl queryLOWithActs(int numActs) {

        int acts =
                0;

        if (_OntModel == null) {
            this._OntModel =
                    this.getOntologyModel();
        }
        Boolean laB =
                false;
        Boolean saB =
                false;

        SLDQueryResultImpl queryResults =
                new SLDQueryResultImpl();

        Set<MetadataRecordReference> instancesR =
                new HashSet<MetadataRecordReference>();


        OntClass ld =
                _OntModel.getOntClass(_nsName + "#Learning-Design");
        ExtendedIterator ldInstances =
                ld.listInstances();


        while (ldInstances.hasNext()) {

            Individual ldInstance =
                    (Individual) ldInstances.next();

            ObjectProperty hasElement =
                    _OntModel.getObjectProperty(_nsName + "#method-ref");
            NodeIterator methodInstances =
                    ldInstance.listPropertyValues(hasElement);
            //for each element
            while (methodInstances.hasNext()) {
                Resource methodInstance =
                        (Resource) methodInstances.next();


                ObjectProperty propPlay =
                        _OntModel.getObjectProperty(_nsName + "#play-ref");
                StmtIterator playInstances =
                        methodInstance.listProperties(propPlay);

                while (playInstances.hasNext()) {
                    Statement playInstance =
                            playInstances.nextStatement();

                    ObjectProperty propAct =
                            _OntModel.getObjectProperty(_nsName + "#act-ref");
                    StmtIterator actInstances =
                            playInstance.getResource().listProperties(propAct);

                    while (actInstances.hasNext()) {
                        Statement stAct =
                                actInstances.nextStatement();
                        acts++;

                    }

                }//plays
            }//methods


            if (numActs == acts) {
                MetadataRecordReference lor =
                        new MetadataRecordReferenceImpl(_rep.getRepositoryURI(),
                        ldInstance.getLocalName());
                if (!(queryResults.getMetadataRecordReference().contains(lor))) {
                    queryResults.getMetadataRecordReference().add(lor);
                }
            }
            saB =
                    false;
            laB =
                    false;
        }

        return queryResults;

    }

    /**
     * Launches a query for  a particular element in the ontology    
     * @return SLDQueryResultImpl
     */
    public SLDQueryResultImpl queryLOWithXRolePartsInAct(int numRoleParts) {
        int roles =
                0;

        if (_OntModel == null) {
            this._OntModel =
                    this.getOntologyModel();
        }
        Boolean laB =
                false;
        Boolean saB =
                false;

        SLDQueryResultImpl queryResults =
                new SLDQueryResultImpl();

        Set<MetadataRecordReference> instancesR =
                new HashSet<MetadataRecordReference>();


        OntClass ld =
                _OntModel.getOntClass(_nsName + "#Learning-Design");
        ExtendedIterator ldInstances =
                ld.listInstances();


        while (ldInstances.hasNext()) {

            Individual ldInstance =
                    (Individual) ldInstances.next();

            ObjectProperty hasElement =
                    _OntModel.getObjectProperty(_nsName + "#method-ref");
            NodeIterator methodInstances =
                    ldInstance.listPropertyValues(hasElement);
            //for each element
            while (methodInstances.hasNext()) {
                Resource methodInstance =
                        (Resource) methodInstances.next();


                ObjectProperty propPlay =
                        _OntModel.getObjectProperty(_nsName + "#play-ref");
                StmtIterator playInstances =
                        methodInstance.listProperties(propPlay);

                while (playInstances.hasNext()) {
                    Statement playInstance =
                            playInstances.nextStatement();

                    ObjectProperty propAct =
                            _OntModel.getObjectProperty(_nsName + "#act-ref");
                    StmtIterator actInstances =
                            playInstance.getResource().listProperties(propAct);

                    while (actInstances.hasNext()) {
                        Statement actInstance =
                                actInstances.nextStatement();

                        ObjectProperty rolePartProp =
                                _OntModel.getObjectProperty(_nsName +
                                "#role-part-ref");
                        StmtIterator rpInstances =
                                actInstance.getResource().listProperties(rolePartProp);

                        while (rpInstances.hasNext()) {
                            Statement rpInstance =
                                    rpInstances.nextStatement();
                            roles++;
                        }
                    }
                }
            }//methods


            if (numRoleParts == roles) {
                MetadataRecordReference lor =
                        new MetadataRecordReferenceImpl(_rep.getRepositoryURI(),
                        ldInstance.getLocalName());
                if (!(queryResults.getMetadataRecordReference().contains(lor))) {
                    queryResults.getMetadataRecordReference().add(lor);
                }
            }
            saB =
                    false;
            laB =
                    false;
        }

        return queryResults;

    }

    /**
     * Launches a query for  a particular element in the ontology    
     * @return SLDQueryResultImpl
     */
    public SLDQueryResultImpl queryLOWhichRolePartsContainsOnlyLA() {
        if (_OntModel == null) {
            this._OntModel =
                    this.getOntologyModel();
        }
        Boolean laB =
                false;
        Boolean saB =
                true;

        SLDQueryResultImpl queryResults =
                new SLDQueryResultImpl();

        Set<MetadataRecordReference> instancesR =
                new HashSet<MetadataRecordReference>();


        OntClass ld =
                _OntModel.getOntClass(_nsName + "#Learning-Design");
        ExtendedIterator ldInstances =
                ld.listInstances();


        while (ldInstances.hasNext()) {

            Individual ldInstance =
                    (Individual) ldInstances.next();

            ObjectProperty hasElement =
                    _OntModel.getObjectProperty(_nsName + "#method-ref");
            NodeIterator methodInstances =
                    ldInstance.listPropertyValues(hasElement);
            //for each element
            while (methodInstances.hasNext()) {
                Resource methodInstance =
                        (Resource) methodInstances.next();


                ObjectProperty propPlay =
                        _OntModel.getObjectProperty(_nsName + "#play-ref");
                StmtIterator playInstances =
                        methodInstance.listProperties(propPlay);

                while (playInstances.hasNext()) {
                    Statement playInstance =
                            playInstances.nextStatement();

                    ObjectProperty propAct =
                            _OntModel.getObjectProperty(_nsName + "#act-ref");
                    StmtIterator actInstances =
                            playInstance.getResource().listProperties(propAct);

                    while (actInstances.hasNext()) {
                        Statement actInstance =
                                actInstances.nextStatement();

                        ObjectProperty rolePartProp =
                                _OntModel.getObjectProperty(_nsName +
                                "#role-part-ref");
                        StmtIterator rpInstances =
                                actInstance.getResource().listProperties(rolePartProp);

                        while (rpInstances.hasNext()) {
                            Statement rpInstance =
                                    rpInstances.nextStatement();
                            ObjectProperty saProp =
                                    _OntModel.getObjectProperty(_nsName +
                                    "#support-activity-ref");
                            StmtIterator sa =
                                    null;
                            sa =
                                    rpInstance.getResource().listProperties(saProp);

                            if (!sa.hasNext()) {
                                saB =
                                        true;
                            }

                            ObjectProperty laProp =
                                    _OntModel.getObjectProperty(_nsName +
                                    "#learning-activity-ref");
                            StmtIterator la =
                                    null;
                            la =
                                    rpInstance.getResource().listProperties(laProp);
                            if (la.hasNext()) {
                                laB =
                                        true;
                            }
                        }
                    }
                }
            }


            if ((saB) && (laB)) {
                MetadataRecordReference lor =
                        new MetadataRecordReferenceImpl(_rep.getRepositoryURI(),
                        ldInstance.getLocalName());
                if (!(queryResults.getMetadataRecordReference().contains(lor))) {
                    queryResults.getMetadataRecordReference().add(lor);
                }
            }
            saB =
                    false;
            laB =
                    false;
        }

        return queryResults;

    }

    /**
     * Launches a query for  a particular element in the ontology    
     * @return SLDQueryResultImpl
     */
    public SLDQueryResultImpl queryLOwithActivitiesWithASpecificRole(String role) {
        if (_OntModel == null) {
            this._OntModel =
                    this.getOntologyModel();
        }
        Boolean laB =
                false;
        Boolean saB =
                true;

        SLDQueryResultImpl queryResults =
                new SLDQueryResultImpl();

        Set<MetadataRecordReference> instancesR =
                new HashSet<MetadataRecordReference>();


        OntClass ld =
                _OntModel.getOntClass(_nsName + "#Learning-Design");
        ExtendedIterator ldInstances =
                ld.listInstances();


        while (ldInstances.hasNext()) {

            Individual ldInstance =
                    (Individual) ldInstances.next();

            ObjectProperty hasElement =
                    _OntModel.getObjectProperty(_nsName + "#method-ref");
            NodeIterator methodInstances =
                    ldInstance.listPropertyValues(hasElement);
            //for each element
            while (methodInstances.hasNext()) {
                Resource methodInstance =
                        (Resource) methodInstances.next();


                ObjectProperty propPlay =
                        _OntModel.getObjectProperty(_nsName + "#play-ref");
                StmtIterator playInstances =
                        methodInstance.listProperties(propPlay);

                while (playInstances.hasNext()) {
                    Statement playInstance =
                            playInstances.nextStatement();

                    ObjectProperty propAct =
                            _OntModel.getObjectProperty(_nsName + "#act-ref");
                    StmtIterator actInstances =
                            playInstance.getResource().listProperties(propAct);

                    while (actInstances.hasNext()) {
                        Statement actInstance =
                                actInstances.nextStatement();

                        ObjectProperty rolePartProp =
                                _OntModel.getObjectProperty(_nsName +
                                "#role-part-ref");
                        StmtIterator rpInstances =
                                actInstance.getResource().listProperties(rolePartProp);

                        while (rpInstances.hasNext()) {
                            Statement rpInstance =
                                    rpInstances.nextStatement();
                            ObjectProperty refProp =
                                    _OntModel.getObjectProperty(_nsName +
                                    "#role-ref");
                            StmtIterator ref =
                                    null;
                            ref =
                                    rpInstance.getResource().listProperties(refProp);


                            //comprobar q es instancia del elemento q buscamos
                            while (ref.hasNext()) {
                                Statement roleRefInstances =
                                        ref.nextStatement();
                                roleRefInstances.getResource();
                            //comprobar si es de esa superclase y si lo es poner el boolean a true
                            }
                        }
                    }
                }
            }


            if ((saB) && (laB)) {
                MetadataRecordReference lor =
                        new MetadataRecordReferenceImpl(_rep.getRepositoryURI(),
                        ldInstance.getLocalName());
                if (!(queryResults.getMetadataRecordReference().contains(lor))) {
                    queryResults.getMetadataRecordReference().add(lor);
                }
            }
            saB =
                    false;
            laB =
                    false;
        }

        return queryResults;

    }

    /**
     * Launches a query for  a particular element in the ontology    
     * @return SLDQueryResultImpl
     */
    public SLDQueryResultImpl queryLOwichComplaintsTheoryOne(HashMap params) {
        System.out.println("Query not yet implemented");
        return null;
    }

    /**
     * Gets the ontology model
     * @return the ontology model asosciated at query manar
     */
    public OntModel getOntologyModel() {
        OntModel ontmodel =
                null;
        for (int i =
                0; i < _onts.size(); i++) {
            Ontology ont =
                    _onts.get(i);

            System.out.println(ont.getNameSpace() + ont.getLocalName());
            String ns =
                    ont.getNameSpace() + ont.getLocalName();
            if (ns.compareTo(_nsName) == 0) {
                ontmodel =
                        ont.getOntModel();

            }
        }
        return ontmodel;
    }
}
